#include <bits/stdc++.h>
using namespace std;

//----fast-read-start----
inline char nc() {
  static char buf[100000], *p1, *p2;
  return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2)
             ? EOF
             : *p1++;
}
template <class T> inline void read(T &x) {
  x = 0;
  char c = nc();
  while (!isdigit(c))
    c = nc();
  while (isdigit(c))
    x = x * 10 + c - '0', c = nc();
}
template <typename T, typename... Args> inline void read(T &t, Args &...args) {
  read(t);
  read(args...);
}
//----fast-read-end----

constexpr int MAXN = 1200 + 5;
constexpr int MAXM = 1.2e5 + 5;

using T = long long int;

struct HLPP {
  const T INF = numeric_limits<T>::max();
  struct edge {
    int to, rev;
    T f;
  };

  int maxn, s, t;

  std::vector<edge> edges;
  std::vector<int> first_edge;
  int _cur_edge[MAXN];
  int nxt[MAXN];
  int lst[MAXN];
  T excess[MAXN];
  int arc[MAXN];

  int gapNxt[2 * MAXN], gapPrv[2 * MAXN];

  int height[MAXN];
  int highest, highestGap, work;

  vector<int> degs;

  HLPP(vector<int> degrees, int s, int t) {
    this->s = s;
    this->t = t;
    maxn = degrees.size();
    // maxn=输入的n, degree数组长度=n
    // std::cout << "maxn=" << maxn << std::endl;
    // std::cout << "degree数组长度:" << degrees.size() << std::endl;
    assert(maxn <= MAXN);
    first_edge = std::vector<int>(maxn + 1);
    int cnt = 0;
    for (int i = 0; i < maxn; ++i) {
      first_edge[i] = cnt;
      cnt += degrees[i];
    }
    first_edge[maxn] = cnt;
    edges = std::vector<edge>(cnt);
    // copy(first_edge, first_edge + maxn + 1, _cur_edge);
    degs.swap(degrees);
  }

  void addEdge(int from, int to, int f) {
    static std::vector<int> _cur_edge(first_edge);
    edges[_cur_edge[from]] = {to, _cur_edge[to], f};
    edges[_cur_edge[to]] = {from, _cur_edge[from], 0};
    _cur_edge[to]++;
    _cur_edge[from]++;
  }

  void pushLst(int h, int v) {
    nxt[v] = lst[h];
    lst[h] = v;
  }

  void updHeight(int v, int nh) {
    if (height[v] != maxn) {
      gapNxt[gapPrv[v]] = gapNxt[v];
      gapPrv[gapNxt[v]] = gapPrv[v];
    }

    height[v] = nh;
    if (nh == maxn)
      return;

    highestGap = max(highestGap, nh);
    if (excess[v] > 0) {
      highest = max(highest, nh);
      pushLst(nh, v);
    }

    nh += maxn;
    gapNxt[v] = gapNxt[nh];
    gapPrv[v] = nh;
    gapNxt[nh] = v;
    gapPrv[gapNxt[v]] = v;
  }

  void globalRelabel() {
    work = 0;
    fill(height, height + maxn, maxn);
    fill(lst, lst + maxn, -1);
    iota(gapNxt, gapNxt + maxn, 0);
    iota(gapPrv, gapPrv + maxn, 0);
    height[t] = 0;
    std::queue<int> que;
    que.push(t);

    while (que.empty() == false) {
      int v = que.front();
      que.pop();
      for (int ie = first_edge[v]; ie < first_edge[v + 1]; ++ie) {
        auto &e = edges[ie];
        if (height[e.to] == maxn && edges[e.rev].f > 0) {
          que.push(e.to);
          updHeight(e.to, height[v] + 1);
        }
      }
      highest = highestGap = height[v];
    }
  }

  void push(int v, edge &e) {
    T df = min(excess[v], e.f);
    if (df > 0) {
      if (excess[e.to] == 0)
        pushLst(height[e.to], e.to);
      e.f -= df, edges[e.rev].f += df;
      excess[v] -= df, excess[e.to] += df;
    }
  }

  void discharge(int v) {
    int nh = maxn;

    for (int i = arc[v]; i < first_edge[v + 1]; i++) {
      auto &e = edges[i];
      if (e.f > 0) {
        if (height[v] == height[e.to] + 1) {
          push(v, e);
          if (excess[v] <= 0) {
            arc[v] = i;
            return;
          }
        } else
          nh = min(nh, height[e.to] + 1);
      }
    }

    for (int i = first_edge[v]; i < arc[v]; i++) {
      auto &e = edges[i];
      if (e.f > 0) {
        if (height[v] == height[e.to] + 1) {
          push(v, e);
          if (excess[v] <= 0) {
            arc[v] = i;
            return;
          }
        } else
          nh = min(nh, height[e.to] + 1);
      }
    }

    work++;

    if (gapNxt[gapNxt[height[v] + maxn]] != height[v] + maxn) {
      updHeight(v, nh);
    } else {
      int oldH = height[v];
      for (int h = oldH; h < highestGap + 1; h++) {
        for (int i = gapNxt[h + maxn]; i < maxn; i = gapNxt[i]) {
          height[i] = maxn;
        }
        gapNxt[h + maxn] = gapPrv[h + maxn] = h + maxn;
      }
      highestGap = oldH - 1;
    }
  }

  T calc() {
    for (int v = 0; v < maxn; ++v) {
      sort(edges.begin() + first_edge[v], edges.begin() + first_edge[v + 1],
           [](edge &l, edge &r) { return l.to < r.to; });
      for (int i = first_edge[v]; i < first_edge[v + 1]; i++) {
        auto &e = edges[i];
        edges[e.rev].rev = i;
      }
    }

    copy(first_edge.data(), first_edge.data() + maxn, arc);
    fill(excess, excess + maxn, 0);
    excess[s] = INF, excess[t] = -INF;
    globalRelabel();

    for (int ie = first_edge[s]; ie < first_edge[s + 1]; ie++)
      push(s, edges[ie]);

    for (; highest >= 0; highest--) {
      while (lst[highest] != -1) {
        int v = lst[highest];
        lst[highest] = nxt[v];
        if (height[v] == highest) {
          discharge(v);
          if (work > 4 * maxn)
            globalRelabel();
        } else {
          throw std::runtime_error("优先级队列有问题");
        }
      }
    }

    return excess[t] + INF;
  }
};

int main(void) {
  int n, m, s, t;
  read(n, m, s, t);
  s--;
  t--;
  vector<array<int, 3>> v(m);
  vector<int> degs(n);
  for (auto &x : v) {
    read(x[0], x[1], x[2]);
    x[0]--, x[1]--;
    ++degs[x[0]];
    ++degs[x[1]];
  }
  HLPP hlpp(degs, s, t);
  for (auto &x : v)
    hlpp.addEdge(x[0], x[1], x[2]);
  printf("%lld\n", hlpp.calc());
  return 0;
}